/* 
 * File:   CueParser.cpp
 * Author: hao
 * 
 * Created on 2011年4月14日, 下午10:21
 */

#include "CueParser.h"

CueParser::CueParser() :Auto1(32), Auto2(11), Auto3(15), Auto4(16), Auto5(16){
    num = num1 = num2 = 0;
    Init();
}

void CueParser::Init() {

    StringCallback.setPointer(&str);
    NumCallback.setPointer(&num);
    NumCallback1.setPointer(&num1);
    NumCallback2.setPointer(&num2);

    //init Automat1
    Auto1.InsertState(0, 'P', 1);
    Auto1.InsertState(1, 'E', 2);
    Auto1.InsertState(2, 'R', 3);
    Auto1.InsertState(3, 'F', 4);
    Auto1.InsertState(4, 'O', 5);
    Auto1.InsertState(5, 'R', 6);
    Auto1.InsertState(6, 'M', 7);
    Auto1.InsertState(7, 'E', 8);
    Auto1.InsertState(8, 'R', 9);
    Auto1.InsertState(9, ' ', 10);
    Auto1.InsertState(10, '"', 11);
    Auto1.InsertState(11, '"', 12, 11);
    Auto1.InsertState(0, 'T', 13);
    Auto1.InsertState(13, 'I', 14);
    Auto1.InsertState(14, 'T', 15);
    Auto1.InsertState(15, 'L', 16);
    Auto1.InsertState(16, 'E', 17);
    Auto1.InsertState(17, ' ', 18);
    Auto1.InsertState(18, '"', 19);
    Auto1.InsertState(19, '"', 20, 19);
    Auto1.InsertAccState(20);
    Auto1.InsertAccState(12);

    Auto1.InsertAction(11, StringCallback);
    Auto1.InsertAction(19, StringCallback);

    //Init automat2
    Auto2.InsertState(0, 'F', 1);
    Auto2.InsertState(1, 'I', 2);
    Auto2.InsertState(2, 'L', 3);
    Auto2.InsertState(3, 'E', 4);
    Auto2.InsertState(4, ' ', 5);
    Auto2.InsertState(5, '"', 6);
    Auto2.InsertState(6, '"', 7, 6);

    Auto2.InsertAccState(7);

    Auto2.InsertAction(6, StringCallback);

    //Init automat3

    Auto3.InsertState(0, 'T', 1);
    Auto3.InsertState(1, 'R', 2);
    Auto3.InsertState(2, 'A', 3);
    Auto3.InsertState(3, 'C', 4);
    Auto3.InsertState(4, 'K', 5);
    Auto3.InsertState(5, ' ', 6);
    for (int i = 0; i < 10; i++)
        Auto3.InsertState(6, '0' + i, 6);
    Auto3.InsertState(6, ' ', 7);
    Auto3.InsertState(7, 'A', 8);
    Auto3.InsertState(8, 'U', 9);
    Auto3.InsertState(9, 'D', 10);
    Auto3.InsertState(10, 'I', 11);
    Auto3.InsertState(11, 'O', 12);

    //And state action

    Auto3.InsertAccState(12);

    //Init Automata4

    Auto4.InsertState(0, 'I', 1);
    Auto4.InsertState(1, 'N', 2);
    Auto4.InsertState(2, 'D', 3);
    Auto4.InsertState(3, 'E', 4);
    Auto4.InsertState(4, 'X', 5);
    Auto4.InsertState(5, ' ', 6);
    Auto4.InsertState(6, '0', 7);
    Auto4.InsertState(7, '1', 8);
    Auto4.InsertState(8, ' ', 9);
    for (int i = 0; i < 10; i++)
        Auto4.InsertState(9, '0' + i, 9);
    Auto4.InsertState(9, ':', 10);
    for (int i = 0; i < 10; i++)
        Auto4.InsertState(10, '0' + i, 10);
    Auto4.InsertState(10, ':', 11);
    for (int i = 0; i < 10; i++)
        Auto4.InsertState(11, '0' + i, 11, 12);

    Auto4.InsertAccState(12);

    //Add state action

    Auto4.InsertAction(9, NumCallback);

    Auto4.InsertAction(10, NumCallback1);

    Auto4.InsertAction(11, NumCallback2);

    //Init Automata5

    Auto5.InsertState(0, 'I', 1);
    Auto5.InsertState(1, 'N', 2);
    Auto5.InsertState(2, 'D', 3);
    Auto5.InsertState(3, 'E', 4);
    Auto5.InsertState(4, 'X', 5);
    Auto5.InsertState(5, ' ', 6);
    Auto5.InsertState(6, '0', 7);
    Auto5.InsertState(7, '0', 8);
    Auto5.InsertState(8, ' ', 9);
    for (int i = 0; i < 10; i++)
        Auto5.InsertState(9, '0' + i, 9);
    Auto5.InsertState(9, ':', 10);
    for (int i = 0; i < 10; i++)
        Auto5.InsertState(10, '0' + i, 10);
    Auto5.InsertState(10, ':', 11);
    for (int i = 0; i < 10; i++)
        Auto5.InsertState(11, '0' + i, 11, 12);

    Auto5.InsertAccState(12);

    //Add state action

    Auto5.InsertAction(9, NumCallback);

    Auto5.InsertAction(10, NumCallback1);

    Auto5.InsertAction(11, NumCallback2);

}

CueSheet CueParser::AnalysisCUE(const char * szPath) {

    int file;

    file = open(szPath, O_RDONLY);

    if (file == -1)
        throw Error(ErrorTag::CUE_FILE_NOT_FOUND);

    struct stat Buf;

    int pos = 0;

    fstat(file, &Buf);

    char * pData = (char *) mmap(NULL, Buf.st_size, PROT_READ, MAP_SHARED,
            file, 0);

    CueSheet sheet;

    sheet.patch = szPath;

    //分析CUE头部标识

    int state;
    
    int currentfileindex = -1;

    Track temp;
    temp.Frame = 0;
    temp.Min = 0;
    temp.Second = 0;
    temp.SpaceFrame = 0;
    temp.SpaceMin = 0;
    temp.SpaceSecond = 0;

    bool bTrack = false;

    do {

        if (bTrack) {
            
            if( currentfileindex == -1 ) throw Error( ErrorTag::CUE_SYTAX_ERROR );

            state = Auto1.Run(pData, Buf.st_size, pos);

            if (state != -1) {
                if (state == 12) {
                    temp.Performer = str;
                    str.clear();
                } else {
                    temp.Title = str;
                    str.clear();
                }
                continue;
            }

            state = Auto5.Run(pData, Buf.st_size, pos);

            if (state != -1) {

                temp.SpaceMin = num;
                temp.SpaceSecond = num1;
                temp.SpaceFrame = num2;
                num = num1 = num2 = 0;
                continue;

            }

            state = Auto4.Run(pData, Buf.st_size, pos);

            if (state != -1) {

                temp.Min = num;
                temp.Second = num1;
                temp.Frame = num2;
                num = num1 = num2 = 0;
                continue;

            }

            state = Auto3.Run(pData, Buf.st_size, pos);

            if (state != -1) {
                sheet.TrackList.push_back(temp);
                temp.fileIndex = currentfileindex;
                temp.SpaceFrame = 0;
                temp.SpaceMin = 0;
                temp.SpaceSecond = 0;
                continue;
            }
            
            state = Auto2.Run(pData, Buf.st_size, pos);

            if (state != -1) {
                sheet.vFilename.push_back( str );
                currentfileindex = sheet.vFilename.size() - 1;
                str.clear();
                continue;
            }

        } else {

            state = Auto1.Run(pData, Buf.st_size, pos);

            if (state != -1) {
                if (state == 12) {
                    sheet.Performer = str;
                    str.clear();
                } else {
                    sheet.Title = str;
                    str.clear();
                }
                continue;
            }

            state = Auto2.Run(pData, Buf.st_size, pos);

            if (state != -1) {
                sheet.vFilename.push_back( str );
                currentfileindex = 0;
                temp.fileIndex = currentfileindex;
                str.clear();
                continue;
            }

            state = Auto3.Run(pData, Buf.st_size, pos);

            if (state != -1) {

                bTrack = true;
                continue;

            }

        }

        pos++;

    } while (pos < Buf.st_size);

    sheet.TrackList.push_back(temp);

    munmap(pData, Buf.st_size);

    close(file);

    return sheet;

}

CueParser::~CueParser() {
}

